/**
 * 这个包是专门放shiro权限管理框架  所需要写的类的：
 *      如：一、自定义realm类（去数据库验证数据  代替shiro默认的去配置文件shiro.ini中去验证数据）
 *              【注意：这个自定义realm类中就是shiro认证的核心代码】
 *          二、SpringBoot整合shiro的配置【配置类】  需要装配项目中对应的要验证信息的对象
 *          以及设置shiro提供的过滤器的拦截规则
 * */
package com.baizhi.shiro;

import com.baizhi.dao.CmfzAdminDao;
import com.baizhi.entity.CmfzAdmin;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

/*
* 问题：
*   在shiro的源码中 默认实现是 拿着用户在页面输入的账号 去配置文件中查询数据
    我们的思路是修改/取代shiro的默认实现，修改为查询数据库，怎么修改呢？ 继承 多态
*解决方法：
    shiro中提供了一个方法
    1. 创建一个realm类 继承 AuthenticatingRealm 类【抽象的认证类】
    2. 重写其中的方法 doGetAuthenticationInfo 【获取认证信息  可以取代默认的获取配置文件的实现】
*/
@Slf4j
public class ShiroRealm extends AuthenticatingRealm {//这就是自定义的realm类
    //    装配一个持明法洲管理员dao的对象 用来查询数据库
    @Autowired
    private CmfzAdminDao cmfzAdminDao;
    @Override
    //重写获取认证信息的方法  参数是个令牌token对象
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//        1.从token中获取用户页面输入的账号  将参数token对象强转为UsernamePasswordToken
//        这个UsernamePasswordToken对象中有直接获取账户和密码的方法
        log.info("自定义realm类执行了");
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
//        2.根据用户名去数据库中查询对应的用户的数据
//        我们负责提供数据 框架完成功能
//        构造查询条件对象  根据用户名查询数据库
        QueryWrapper<CmfzAdmin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        CmfzAdmin cmfzAdmin = cmfzAdminDao.selectOne(queryWrapper);
//        3.判断查询结果是否为null  如果为null,则直接返回null  否则返回一个封装后的info对象
        /**info对象的创建  new出来的  需要三个参数(若是用了加密规则 则需要4个参数)
         * new SimpleAccount（账户，密码，this.getName()）
         * 参数1 数据库查询到的账号
         * 参数2 数据库查询到的密码
         * 补充参数3：从数据库中查询的盐值salt  并且要处理为ByteSource类型的
         * 参数4 当前对象的名字
         */
        if(cmfzAdmin!=null){
            log.info("自定义realm类中查询出的管理员对象："+cmfzAdmin);
            //获取管理员对象中的盐值
            String salt = cmfzAdmin.getSalt();
            //处理盐值 为ByteSource类型的数据  【ByteSource为shiro框架下的类】
            ByteSource bytes = ByteSource.Util.bytes(salt);
            return new SimpleAccount(cmfzAdmin.getUsername(),cmfzAdmin.getPassword(),bytes,this.getName());
        }
        return null;
    }
}
